
local skynet = require "skynet"
local log = require "Log"
local config = require "configquery"
local Timer = require "timer"
local FSM = require "fsm"
local NodeMessage = require "NodeMessage"
local Universal = require "Universal"
local json = require "cjson"
require "common"


local mix_array = mix_array
local table_clone = table_clone
local floor = math.floor
local four_five = math.four_five
local random = math.random

local MachineBase = require "common.MachineBase"
local Machine = class("Machine2",MachineBase)


function Machine:ctor(tableid,rule)
	json.encode_sparse_array(true)
	self.super:ctor(tableid,rule) --父类
	self.tbSeatCard = {} --座位上的牌
	self.tbSeatRes = {} --座位结果
	self.winnerSeat = nil --赢家座位
	self.operSeatid = nil --当前操作的座位
	self.startSeatid = 1 --开始操作的座位id
	self.nextOperSeat = true --下个玩家操作
	self.tbCurSeatCard = {} --座位上当前的牌
	self.curCards = {} --当前已出的一手牌
	self.curCardType = nil --当前已出的一手牌型
	self.curCardCode = nil --当前桌上面的特征码
	self.tbOutCard = {} --所有已打出的牌
	self.cardIsSeat = nil --桌面牌是那个座位出的
	self.winnerSeatId = nil --赢家座位
	self.tipCards = nil --提示可以出的牌
	self.winChip = 0 --玩家赢的筹码
	self.curRound = 0 --当前轮
	self.firstCard = 33 --有红桃3的先出牌
	self.tbUseBomb = {} --座位使用的炸弹数
	self.tbCloseCard = {} --对应座位是否被关牌
	self.tbRestCard = {} --记牌，对应各个座位
	self.waitTime = 0 --桌子等待开始的时间 
	self.maxWaitTime = 60*30 --桌子等待开始的时间 
	self.lastSeat = nil --倒数第二出牌的人
	self.cardNum = 15  --牌张数
	self.lastSeatCard = {} --每个位置最后出的一首牌
	self.curJuShu = 0 --第几局
	self.tbCloseVote = {} --请求解散桌子
	self.closeVoteTime = 90 --投票解散桌子时间
	self.fangkaEnd = false --桌子已结束
	self.tbCardRecord = {
		game_start={}, --游戏开始时玩家信息
		game_end={}, --游戏结束时玩家信息
		game_oper={}, --游戏操作过程
		game_config={}, --游戏设置
	} --牌局记录表
	self.tbSeatOutCard = {} --已出的牌的位置

	--房卡配置
	-- local data = self.nodeMessage:callService('dbmgr_service','reload_private_tables',tableid)
	local sql = string.format("select * from private_tables where tableid = %d", tableid)
	local data = skynet.call("mysql_service", "lua", "execute", sql)	
	data = data[1]	
	if not data then 
		log.error("_____创房数据有问题___",tableid,sql)
		self:exit()		
	end
	local setting = json.decode(data.setting)
	print("___________setting____",setting)

	self.maxJuShu = setting.play_count or 0 --最大局数
	self.cardNum = setting.card_num --牌数
	if self.cardNum~=15 or self.cardNum~=16 then 
		self.cardNum = 15
	end
	self.payer = setting.payer --支付者
	self.playType = setting.roomType --玩法类型
	self.cost = setting.cost or 0 --花费
	self.renshu = setting.player_num --人数

	self.tableNum = data.number --房号
	self.manager = nil
	self.managerid = data.managerid --房主id
	self.handlerVoteTime = nil --解散桌子定时器
	self.sourceid = nil --发起者id
	self.voteTime = 120 --投票时间

	if self.payer==2 then --aa付
		self.cost = math.floor(self.cost/self.renshu)
	end
	self.tbChipRecord = {} --每局赢分记录
	self.tbChipZhaDan = {} --炸弹所赢分
	self.room_flag = ""..self.tableid..os.time()--大局唯一标识
	self.operList = {		
		deal =1,		--出牌			
		tip = 2, 		--提示
		play_next = 3,	--不出牌		
	}	
	self.playerState = {		
		playing = 1, --正常
		auto = 2,	--托管		
		ready = 3,  --已准备
		disconnect = 4, --离线		
	}	
	--状态时间
	self.statusTime = {
		wait = 1,		--等待时间
		rest = 5,		--休息时间
		start = 4,		--开始
		oper = 10,		--出牌操作时间	
		lastcard = 2,	--最后一手出牌时间	
		settlement = 1, --结算时间
	}
	--状态
	--等侍，休息，开始， 玩家操作(8轮)，比牌，结算
	--state1 --eventName --state2 --callback
	self.gameStateTransitionTable = {
		{"rest", 		"to_start", 			"start", 		function() self:onStart() end },
		{"start", 		"to_oper",				"oper", 		function() self:onOper() end },			
		{"oper", 		"to_lastcard",			"lastcard", 	function() self:onLastCard() end },
		{"lastcard", 	"to_settlement",		"settlement", 	function() self:onSettlement() end },
		{"settlement", 	"to_rest", 				"rest", 		function() self:onRest() end},
		{"rest", 		"to_wait", 				"wait", 		function() self:onWait() end},		
		{"wait", 		"to_rest", 				"rest", 		function() self:onRest() end},	
	}
	--状态机
	self.fsm = FSM.new(self.gameStateTransitionTable)

	local tbStateTransitoin = {
		{"rest", 		"to_start", 			"start", 		function() self:onStartVote() end },
		{"start", 		"to_end", 				"end", 			function() self:onEndVote() end },
		{"start", 		"to_rest", 				"rest", 		function() self:onRestVote() end },
	}
	--状态机
	self.fsm2 = FSM.new(tbStateTransitoin)
	self.fsm2:set("rest")

	self:reset()
end

---------------------------------------------------------
-- private
---------------------------------------------------------
--重置数据
function Machine:reset()
	self.operStartTime = 0
	self.tbCurSeatCard = {} --座位上当前的牌
	self.curCards = {} --当前已出的一手牌
	self.cardIsSeat = nil --桌面牌是那个座位出的
	self.winnerSeatId = nil --赢家座位
	self.tipCards = nil --提示可以出的牌
	self.winChip = 0 --玩家赢的筹码
	self.operSeatid = nil
	self.curCardCode = nil --当前桌上面的特征码
	self.curRound = 0 --当前轮
	self.curCardType = nil --当前已出牌型
	self.startSeatid = nil
	self.tbUseBomb = {} --座位使用的炸弹数
	self.tbCloseCard = {} --对应座位是否被关牌
	self.nextOperSeat = true
	self.lastSeat = nil
	self.lastSeatCard = {}
	self.tbOutCard = {}
	self.tbChipRecord = {} --每局赢分记录
	self.tbChipZhaDan = {} --炸弹所赢分
	self.tbSeatOutCard = {}
	self.tbCardRecord = {
		game_start={}, --游戏开始时玩家信息
		game_end={}, --游戏结束时玩家信息
		game_oper={}, --游戏操作过程
		game_config={}, --游戏设置
	} --牌局记录表
	--玩家自身状态
	for k,v in pairs(self.player_list) do 
		v.playing = false			
		v.oper = nil
		v.look = nil
		v.auto = nil
		self.tbChipZhaDan[k]=0
	end
end

--玩家状态值 
function Machine:getPlayerState(player)
	local state = 0 	
	if player.ready then 
		state = self.playerState.ready
	end	
	if player.playing then
		state = self.playerState.playing
	end
	if player.auto then
		state = self.playerState.auto
	end		
	if player.disconnect then
		state = self.playerState.disconnect
	end			
	return state
end

--玩家可作操作列表
function Machine:getPlayerOperList(player)
	local tbOper = {}
	if player.oper == self.operList.play_next then
		table.insert(tbOper,self.operList.play_next)
	else
		table.insert(tbOper,self.operList.deal)
		table.insert(tbOper,self.operList.tip)
	end
	return tbOper
end

--出牌
function Machine:pushCard(seatid,cards)
	local tbCard = self.tbCurSeatCard[seatid]
	if not cards or not next(cards) then 
		return
	end
	local tbRemove = {}
	--从手牌中移去出的牌
	for k,v in pairs(tbCard) do 
		for _,card in pairs(cards) do 
			if v == card then 
				table.insert(tbRemove,k)
			end
		end
	end
	local function sort(a,b)
		return a>b
	end	
	table.sort(tbRemove,sort)
	for k,v in pairs(tbRemove) do 
		table.remove(tbCard,v)
	end
	log.debug("__pushCard_tbCard___",cards,self.tbCurSeatCard[seatid],seatid)
	--终止托管计时
	self:setTime()
	if next(self.curCards) then 
		--牌不被全关
		self.tbCloseCard[seatid] = false
	end
	self.tbSeatOutCard[seatid] = cards

	self.curCards = cards	
	self.curCardCode,self.curCardType = self.rule:getCardCode(cards)
	self.lastSeat = self.cardIsSeat
	self.cardIsSeat = seatid
	self.lastSeatCard[seatid] = cards
	for k,v in pairs(cards) do 
		table.insert(self.tbOutCard,v)
	end
	--炸弹数统计
	if self.curCardType == self.rule.cardType.zhaDan then 
		if not self.tbUseBomb[seatid] then 
			self.tbUseBomb[seatid] = 1
		else
			self.tbUseBomb[seatid] = self.tbUseBomb[seatid] + 1
		end
	end
	if #tbCard == 0 then 
		log.debug("____结束______winner is ____",seatid)

		self.winnerSeatId = seatid		
		self.fsm:fire("to_lastcard")
		return 
	end	

end

--@override
function Machine:sitDownCallback( playerid )
	log.debug("__1111111111___sitDownCallback_______")
	local player = self:getPlayer(playerid)
	local seatPlayer = self:getSeatPlayer(player)	
	local data = {pdk_nt_seat_change = {
		tableid = self.tableid,
		seatid = player.seatid,
		seat_player = seatPlayer,
		playerid = playerid,		
		leave = false,
	}}	
	self:sendToOther(playerid,data)
end

function Machine:sitUpCallback(seatid,playerid)	
	local data = {pdk_nt_seat_change = {
		tableid = self.tableid,
		seatid = seatid,
		playerid = playerid,
		leave = true,
	}}
	log.debug("_____situp___",data)	
	self:sendToAll(data)
	self.player_list[playerid] = nil
end


--加入玩家
function Machine:canJoin(playerid)
	print("______________Machine:canJoin", playerid)
	local num = 0 
	for k,v in pairs(self.player_list) do 
		if k ~= self.managerid then 
			num = num + 1
		end
	end
	if num >= 2 and playerid ~= self.managerid then 
		return false
	end
	return true
end

--加入玩家
function Machine:addPlayer(player)
	print("______________Machine:addPlayer", player)
	self:readUserInfo(player)
	if self.managerid == player.playerid then 
		self.manager = table.copy(player)
		print("________self.manager__",self.manager)
	end
	player.chip = 0
	self.player_list[player.playerid] = player
	self:updatePlayerNum()
end

--离线清除
function Machine:removePlayer()
	for k,v in pairs(self.player_list) do 	
		if v.disconnect and not v.ready and k~=self.managerid then 				
			--设置玩家所在桌子id为0	
			self:sendGate(v, 'update_tableid', 0)
			self:sitUp(k)
			self.player_list[k] = nil
			self:updatePlayerNum()
			print("踢走掉线 o#######",k,v.disconnect,v.chip,self.minChip)
		end
	end
end

--删除桌子
function Machine:deleteTable(playerid)
	local data = {nt_manager_close={
		playerid=playerid,
		tableid=self.tableid,
	}}
	self:sendToAll(data)
	print("_______closePrivate___",data)
	self.fangkaEnd = true
		
	--返还房卡
	local player = self:getPlayer(playerid)
	print("_______22_self.manager__",player)
	if player then 
		--在房间中
		local fangka = self:callGate(player, 'change_fangka', self.cost, reason)		
		if not fangka then --玩家不在线直接改数据库
			local sql = string.format("update usergame set room_ticket=room_ticket + %d where uid=%d",
				self.cost,playerid)		
			self.nodeMessage:sendService("mysql_service","execute", sql)		
		end
		for k,v in pairs(self.player_list) do 			
			--aa支付
			if k~=self.managerid and self.payer==2 then 
				--返卡
				if v.ready then 
					local fangka = self:callGate(v, 'change_fangka', self.cost, reason)		
					if fangka then 	
						local sql = string.format("update usergame set room_ticket=room_ticket + %d where uid=%d",
							self.cost,k)		
						self.nodeMessage:sendService("mysql_service","execute", sql)								
					end				
				end
			end	
		end

		self.nodeMessage:callGlobalService('tablestate','close_private',playerid, self.tableid)	
		self:voteTable()		
	else
		--重启服务器，会出现这种情况 只改数据库
		for k,v in pairs(self.player_list) do 			
			--aa支付
			if k~=self.managerid and self.payer==2 then 
				--返卡
				if v.ready then 
					local fangka = self:callGate(v, 'change_fangka', self.cost, reason)		
					if fangka then 	
						local sql = string.format("update usergame set room_ticket=room_ticket + %d where uid=%d",
							self.cost,k)		
						self.nodeMessage:sendService("mysql_service","execute", sql)								
					end				
				end
			end	
		end		

		self.nodeMessage:callGlobalService('tablestate','close_private',playerid, self.tableid)	
		self:voteTable()		
		log.debug("____房主开房好不在桌子里，",self.tableid,self.managerid)
	end

end
--激活关桌子
function Machine:closePrivate(playerid)
	print("_______playerid___",playerid,self.managerid)
	if playerid~=self.managerid then 
		return false
	end
	--没开局直接解散，开局后要投票
	if self.curJuShu > 0 then 
		self.tbCloseVote[playerid] = 1
		self:ntCloseVote()
		self.fsm2:fire("to_start")
		return false
	else
		self:deleteTable(self.managerid)
	end
	return true
end

--同意关桌子
function Machine:closeVote(playerid,args)
	print("________pdk_close_vote_req___111",self.tbCloseVote)
	if next(self.tbCloseVote) then
		if self.tbCloseVote[playerid] then  
			return false
		end
	else
		self.sourceid = playerid
		self.fsm2:fire("to_start")
	end
	print("________pdk_close_vote_req___2222")
	if args.agree then 
		self.tbCloseVote[playerid] = 1
	else
		self.tbCloseVote[playerid] = 2 --拒绝
	end
	local allClose = true
	for k,v in pairs(self.player_list) do 
		if not v.disconnect then 
			if not self.tbCloseVote[k] or self.tbCloseVote[k]==2 then 
				allClose = false
				break
			end
		end
	end
	print("________pdk_close_vote_req__3333",allClose)
	if allClose then 
		--所有已关闭，解散桌子
		self.fsm2:fire("to_end")
	else
		--通知同意的人数增加了
		self:ntCloseVote()	
		if self.tbCloseVote[playerid]==2 then
			self.fsm2:fire("to_rest")
		end	
	end
	return true
end


---------------------------------------------------------
-- 状态
---------------------------------------------------------
--等侍
function Machine:onWait()
	-- log.debug("_______wait")
	local timehandler = nil
	local callback = function()
		if timehandler then
			return 
		end	
		-- self:removeDisconnect()
		self:removePlayer()
		--人数足2个才开始
		local num = 0
		local robotNum = 0
		for k,v in pairs(self.player_list) do 		
			if v.noReadyTime then
				v.noReadyTime = v.noReadyTime + self.statusTime.wait
				if v.noReadyTime > 10 then 
					--清除没准备的玩家
					v.noReadyTime = 0
					-- self:removeNoReady()
				end
			end		
			if v.ready then 		
				num = num + 1
			end
			if v.robot then 
				robotNum = robotNum + 1
			end			
		end
		if self.curJuShu==0 then 
			self.waitTime = self.waitTime + self.statusTime.wait
			-- print("___self.waitTime__",self.waitTime,num)
			if self.waitTime>self.maxWaitTime then
				--没有开始10分钟后解散桌子
				log.debug("时间到没开始解散桌子",self.tableid,self.managerid)
				self.waitTime = 0
				self:deleteTable(self.managerid)
			end
		end
		-- if num>0 and robotNum<3 and self.waitTime>4 then 
		-- 	self.waitTime = 0
		-- 	local data = {
		-- 		gameid = self.gameid,
		-- 		roomid = self.roomid,
		-- 		tableid = self.tableid,
		-- 		num = 1,
		-- 	}
		-- 	self.nodeMessage:sendGlobalService('robot_service','rb_nt_add',data)
		-- end

		if num < 3 then 
			return
		end		
		--
		local callback2 = function ( )		
			self.fsm:fire("to_rest")			
		end
		timehandler = self.timer:register(self.statusTime.wait,nil,callback2)
				
	end
	self:setTime(self.statusTime.wait,callback,true)
end

--休息
function Machine:onRest()
	print("_______rest")
	self.operStartTime = os.time()
	--洗牌
	self.rule:shuffle(self.cardNum)
	--重置数据
	self:reset()
	--通知客户端
	self:ntRest()
	self:removePlayer()
	local function  checkPlayer()
		--人数足3个才开始
		local num = self:getReadyNum()
		if self.fangkaEnd then 
			return 
		end
		if num < 3 or self.handlerVoteTime  then 
			self.fsm:fire("to_wait")
			return false
		end	
		if self.close then --已关服
			return false
		end
		if self.curJuShu == self.maxJuShu then 
			--总结算
			self:ntFangkaEnd()
			return false
		end
		self.fsm:fire("to_start")
		-- return true
	end
	if not checkPlayer() then 
		return 
	end

end

--开始
function Machine:onStart()
	print("_______start")		
	self.operStartTime = os.time()	
	
	local allBottomChip = 0	
	local player
	local money
	local cards
	self.paijuid = getRoundId(self.tableid)
	self.curJuShu = self.curJuShu + 1 --局数
	self.waitTime = 0

	--准备好的玩家
	for seatid,playerid in pairs(self.seat_list) do 
		player = self.player_list[playerid]
		if player.ready then 
			player.playing = true
		end
		player.noReadyTime = 0
		cards = self.rule:getCard(self.cardNum)		
		self.tbSeatCard[seatid] = cards
		self.tbCurSeatCard[seatid] = table.copy(cards)
		if not self.startSeatid then 
			for _,v in pairs(cards) do 
				if v == self.firstCard then
					self.startSeatid = seatid 
					break
				end
			end
		end
		self.tbCloseCard[seatid] = true
		local tb = {seatid=seatid,playerid=playerid,nick=player.nick,chip=player.chip,cards=cards}
		table.insert(self.tbCardRecord.game_start,tb)

	end
	for seatid,playerid in pairs(self.seat_list) do 
		local data = {pdk_nt_start={
	 		tableid = self.tableid,	
	 		paijuid = self.paijuid, 
	 		cards = self.tbSeatCard[seatid],
	 		seatid = self.startSeatid,
	 		first_card = self.firstCard,
		}}		
		log.debug("_______start game_____data____",data)
		--通知到有座玩家拿牌
		self:sendMessage(playerid,data)
	end
	self.tbCardRecord.game_config = {
		start_time=os.time(),		
		end_time=os.time(),
		card_num=self.cardNum, 
		jushu=self.maxJuShu,
		cur_jushu=self.maxJuShu,
		payer=self.payer,
		roomid=self.tableNum,
		owner=self.managerid, 
		bottom_num=self.bottomNum,
		play_type=self.playType,
	}
	--通知无座玩家
	self:ntStart()

	local callback = function()
		self.fsm:fire("to_oper")
	end
	self:setTime(self.statusTime.start,callback)
end

--玩家操作
function Machine:onOper()
	log.debug("_______onOper")		
	local callback = function()	
		if not self.nextOperSeat then 
			return
		end
		local seatid = self:nextOperSeatid()
		if not seatid then 
			return
		end
		if self:getState() ~= 'oper' then 
			return 
		end
		self.operStartTime = os.time()
		local player = self:getPlayerBySeat(self.operSeatid)
		local oldTime = os.time()
		local playerOperFun = function ()
			if self:getState() ~= 'oper' then 
				return 
			end
			--时间到玩家没操作视为托管
			log.debug("__时间到玩家没操作视为托管__",os.time() - oldTime,seatid)
			-- player.auto = true	
			-- self:autoPlay(seatid)	
		end				
		-- if player.auto then 
		-- 	log.debug("_______托管出牌___",self.operSeatid)
		-- 	self:autoPlay(seatid)
		-- else
			self:setTime(self.statusTime.oper,playerOperFun)		
		-- end
	end
	skynet.fork(function()
		while(true) do 
			if self:getState() == 'settlement' then 
				break 
			end
			callback()
			skynet.sleep(30)
		end
	end)
end

--最后一手牌
function Machine:onLastCard()
	local callback = function()
		self.fsm:fire("to_settlement")
	end			
	self:setTime(self.statusTime.lastcard, callback)	
end

--结算
function Machine:onSettlement()
	log.debug("_______settlement")
	self.operStartTime = os.time()	
	local player 	
	local endPlayers = {}
	local endPlayer = {}
	local money
	local winChip = 0
	local failSeatId --包赔者
	local lessCardNum = 0 --剩余牌数
	local tbLessCards --剩余的牌
	local tbJuWin = {}
	--剩余的牌
	for seatid,playerid in pairs(self.seat_list) do 
		if seatid ~= self.winnerSeatId then 
			player = self:getPlayer(playerid)
			tbLessCards = self.tbCurSeatCard[seatid] or {}
			lessCardNum = #tbLessCards
			winChip = self.bottomNum*lessCardNum
			if self.tbCloseCard[seatid] then 
				winChip = winChip * 2
			end
			-- if player.chip < winChip then 
			-- 	winChip = player.chip
			-- end			
			self.winChip = self.winChip + winChip
		end
	end	 
	
	--是否要包赔
	if self.lastSeat ~= self.winnerSeatId then 
		log.debug("_______self.curCards___",self.curCards)
		if self.curCards and #self.curCards == 1 then 
			local tbCard = self.tbCurSeatCard[self.lastSeat]
			local cards = self.lastSeatCard[self.lastSeat]
			-- log.debug("___11111_____tbCard___",tbCard,cards)
			if next(self.rule:getBiggerCard(tbCard,cards)) then 
				failSeatId = self.lastSeat
				log.debug("__________包赔_____",failSeatId)
			end
		end
	end
	-- local reason = {
	-- 	code = 2,
	-- 	moneytype = 1,
	-- 	game = self.gameid%100,
	-- 	gameid = self.gameid%100,
	-- 	gametype = self.roomid,
	-- }
	for seatid,playerid in pairs(self.seat_list) do 
		player = self:getPlayer(playerid)
		winChip = 0
		tbLessCards = self.tbCurSeatCard[seatid] or {}
		lessCardNum = #tbLessCards
		if seatid ~= self.winnerSeatId then 
			--输
			if failSeatId then 
				--包赔
				if failSeatId == seatid then 
					winChip = -self.winChip					
				end
			else
				winChip = -self.bottomNum*lessCardNum	
				if self.tbCloseCard[seatid] then 
					--被全关
					winChip = winChip * 2
				end					
			end
		else
			--赢
			winChip = self.winChip			
		end
	
		-- money = self:callGate(player, 'change_money', winChip, reason)		
		-- if money then 
		-- 	player.chip = money
		-- end
		self.tbChipRecord[playerid]=winChip

		player.chip = player.chip+winChip
		endPlayer = {}
		endPlayer.seatid = seatid
		endPlayer.playerid = playerid
		endPlayer.chip = player.chip
		endPlayer.diamond = player.diamond		
		endPlayer.win_chip = winChip
		endPlayer.cards = tbLessCards
		endPlayer.bomb_num = self.tbUseBomb[seatid] or 0
		endPlayer.be_close = self.tbCloseCard[seatid]
		endPlayer.nick = player.nick or '无名字'
		if endPlayer.nick == "" then 
			endPlayer.nick = '无名字'
		end		
		table.insert(endPlayers,endPlayer)
		--输赢次数写入数据库
		if winChip > 0 then 
			player.uwincnt = player.uwincnt + 1
		elseif winChip < 0 then 
			player.ulosecnt = player.ulosecnt + 1
		else
			player.udrawcnt = player.udrawcnt + 1
		end
		self:writeUserInfo(player)		
	end
	--玩家改为未准备状态
	-- for k,v in pairs(self.player_list) do 
	-- 	v.ready = false	
	-- 	v.playing = false
	-- end	
	
	local callback = function()
		self.fsm:fire("to_rest")
	end			
	self:setTime(self.statusTime.settlement, callback)
	--通知客户端
	self:ntEnd(endPlayers)
	for k,v in pairs(endPlayers) do 
		--炸弹分
		v.bomb_score = self.tbChipZhaDan[v.playerid] or 0
		v.card_score = self.tbChipRecord[v.playerid] or 0
	end
	--牌局记录
	self.tbCardRecord.game_end = endPlayers
	self:paijuRecord()
end


--投票解散
function Machine:startVoteCallback()
	self.closeVoteTime = self.closeVoteTime - 1
	print("___self.closeVoteTime___",self.closeVoteTime)
	local canClose = true
	for k,v in pairs(self.player_list) do 
		if not self.tbCloseVote[k] or self.tbCloseVote[k]==2 then 
			canClose = false
		end
	end
	if canClose or self.closeVoteTime==0 then 
		self.fsm2:fire("to_end")
	end
end
function Machine:onStartVote()
	self.closeVoteTime = self.voteTime
	local callback = function ()		
		self:startVoteCallback()
	end
	self.handlerVoteTime = self.timer:register(1 , nil, callback,true)	
end
function Machine:onEndVote()	
	self.timer:unregister(self.handlerVoteTime)	
	self.handlerVoteTime = nil 	
	self.nodeMessage:callGlobalService('tablestate','close_private',playerid, self.tableid)			
	self:ntFangkaEnd()
	-- self.fsm2:fire("to_rest")
end
function Machine:onRestVote()
	self.timer:unregister(self.handlerVoteTime)	
	self.handlerVoteTime = nil 
	self.tbCloseVote = {}
end
-----------------------

--设置当前操作的座位
function Machine:nextOperSeatid()
	local player
	local operSeatid = self.operSeatid
	self.nextOperSeat = false
	if not operSeatid then --从上局赢家开始操作
		operSeatid = self.startSeatid
		player = self:getPlayerBySeat(operSeatid)
		if self:isPlaying(player) then 
			self.curRound = 1
			log.debug("_111_______________ 当前轮数_____",self.curRound)
			self.operSeatid = operSeatid
			self:ntOper(operSeatid)
			return operSeatid			
		end
	end
	-- while(true) do 
		operSeatid = operSeatid + 1
		if operSeatid > self.maxSeatNum then 
			operSeatid = 1
		end		
		
		-- player = self:getPlayerBySeat(operSeatid)
		-- if self:isPlaying(player) then 
			-- break
		-- end
	-- end
	local oldOperSeat = self.operSeatid
	self.operSeatid = operSeatid
	self:ntOper(operSeatid,oldOperSeat)
	if operSeatid == self.startSeatid then --1轮结束						
		self.curRound = self.curRound + 1
		log.debug("______ 当前轮数_____",self.curRound,operSeatid,self.startSeatid)
	end	

	return operSeatid
end

--托管操作
function Machine:autoPlay(seatid)
	local player = self:getPlayerBySeat(seatid)
	local cards --要出的牌
	if not player then 
		log.debug('#########error___player giveup 没有此玩家 seatid',seatid)
		return
	end
	if seatid ~= self.operSeatid then
		return 
	end	
	log.debug('#########__autoPlay_cards ',self.cardIsSeat,seatid,self.tipCards,self.curCards)
	if not self.tipCards then 
		--出不了牌
	else			
		self:pushCard(seatid,self.tipCards)
	end	
	
	--让下个人操作
	self.nextOperSeat = true
	return true
end

--取到提示的牌
function Machine:getTipCards()
	local seatid = self.operSeatid
	local player = self:getPlayerBySeat(seatid)
	local cards
	if not next(self.curCards) or self.cardIsSeat==seatid then 	
		cards = self.rule:getCardByType(self.tbCurSeatCard[seatid])		
	else
		local tb = self.rule:getBiggerCard(self.tbCurSeatCard[seatid],self.curCards)
		if tb and next(tb) then 
			cards = tb[1]
		end
	end	
	log.debug("__________self.tipCards___",cards,self.tbCurSeatCard[seatid])
	self.tipCards = cards 
	if not cards or not next(cards) then 
		player.oper = self.operList.play_next 
	else
		player.oper = self.operList.deal 
	end

end
---------------------------------------------------------
-- public
---------------------------------------------------------

--取桌子状态
function Machine:getTableStatus(playerid)
	local seatPlayer
	local seatPlayers = {}
	local player = self:getPlayer(playerid)

	-- log.debug("__self.seat_list__",self.seat_list)
	for seatid,pid in pairs(self.seat_list) do
		if pid>0 then
			player = self.player_list[pid]			
			seatPlayer = self:getSeatPlayer(player)
			seatPlayer.oper_time = 0
			seatPlayer.state = self:getPlayerState(player)
			if seatid == self.operSeatid then --正在操作
				local operTime = self.statusTime.oper - (os.time() - self.operStartTime)
				if operTime > 0 then
					seatPlayer.oper_time = operTime
				end
				seatPlayer.button_list = self:getPlayerOperList(player)				
			end
			if seatPlayer.playing then --正在玩有牌
				local tb = self.tbCurSeatCard[seatid]
				if tb and next(tb) then
					local tbTemp = tb
					if playerid ~= player.playerid then 	
						tbTemp = {}		
						log.debug("_______tbCurSeatCard____",tb,pid)			
						for i=1,#tb do 
							table.insert(tbTemp,0)
						end 
					end
					seatPlayer.card_data = tbTemp
				end
				if player.look then --明牌						    
					seatPlayer.card_data  = self.tbSeatRes[seatid]
		        end
			end
			table.insert(seatPlayers,seatPlayer)
		end
	end	
	local code 
	if next(self.curCards) then 
		code = self.rule:getCardCode(self.curCards)
	end
	local status = {		
		seat_player = seatPlayers,
		config = self:getConfig(),
	}	
	if code then 
		-- status.cards = self.curCards
		-- status.card_seat = self.cardIsSeat
		status.code = code
	end		
	print("__________1",self.tbSeatOutCard,self.operSeatid)
	if self.operSeatid then 
		self.tbSeatOutCard[self.operSeatid] = nil
	end
	local tbOurCard = {}
	local tb
	for k,v in pairs(self.tbSeatOutCard) do 
		tb = {}
		tb.cards = v
		tb.seatid = k
		tb.code = self.rule:getCardCode(v)
		table.insert(tbOurCard,tb)
	end
	status.seat_out_card = tbOurCard

	if self.handlerVoteTime then 
		--在投票解散
		skynet.fork(function()
			skynet.sleep(50)
			self:ntCloseVote()
		end)
	end
	log.debug("Table status################",status)	
	return status
end

--提示出牌
function Machine:playTip(playerid)
	local player = self:getPlayer(playerid)
	local seatid = player.seatid
	log.debug("_____playTip___",seatid,self.operSeatid,self.tipCards)
	if self:getState() ~= 'oper' then 
		return false
	end
	-- local cards
	if not seatid or seatid == 0 then 
		return false
	end
	if self.operSeatid ~= seatid then
		return false
	end
	return self.tipCards
end

--出牌
function Machine:playDeal(playerid,cards)
	local player = self:getPlayer(playerid)
	local seatid = player.seatid
	local cardType 
	local canPush = false
	if self.operSeatid ~= seatid then 
		return false 
	end
	if self:getState() ~= 'oper' then 
		return false
	end
	if player.auto then 
		--拖管中
		return false
	end
	--验证出的牌是否是在手牌中
	local tbCard = self.tbSeatCard[seatid]
	local hasCard
	for _,card in pairs(cards) do 
		hasCard = false
		for _,hcard in pairs(tbCard) do 
			if card == hcard then 
				hasCard = true
				break
			end
		end
		if not hasCard then 
			return false
		end
	end
	cardType = self.rule:getCardType(cards)	
	log.debug("___deal__cards__",seatid,self.cardIsSeat, cards,self.curCards,cardType)
	if not next(self.curCards) or seatid == self.cardIsSeat then 
		if not cardType then 
			--出牌规则不对
			return false
		end
		self:pushCard(seatid,cards)
		--让下个人操作
		self.nextOperSeat = true	
		return true		
	elseif self.rule:compareCards(cards,self.curCards) then 
		self:pushCard(seatid,cards)
		--让下个人操作
		self.nextOperSeat = true	
		return true		
	end
		
	log.debug("___出牌错误______")
	return false
end

--不出
function Machine:playNext(playerid)
	local player = self:getPlayer(playerid)
	local seatid = player.seatid
	if self.operSeatid ~= seatid then 
		return false 
	end	
	if self:getState() ~= 'oper' then 
		return false
	end	
	if self.tipCards then 
		log.debug("___有牌不出____",playerid,seatid)
		return false	
	end
	self.tbSeatOutCard[seatid] = {}
	--让下个人操作
	self.nextOperSeat = true
	return true
end

--取消托管
function Machine:noAutoPlay(playerid)
	local player = self:getPlayer(playerid)
	local seatid
	if not player then 
		return false
	end
	seatid = player.seatid
	if not seatid or seatid == 0 then 
		return false
	end
	self:ntNoAuto(playerid,seatid)
	player.auto = false
	return true
end

--准备
function Machine:playReady(playerid)
	local player = self:getPlayer(playerid)
	local seatid
	local state
	if not player then 
		return false
	end
	seatid = player.seatid
	if not seatid or seatid == 0 then 
		return false
	end
	player.ready = true
	self:ntReady(playerid,seatid)
	--aa支付
	if self.curJuShu == 0 and self.payer==2 then 
		--扣卡
		if playerid ~= self.managerid then 
			local fangka = self:callGate(player, 'change_fangka', -self.cost, reason)		
			if fangka then 				
			end				
		end
	end	
	return true
end

--记牌处理
function Machine:recordSeatCard(playerid)
	local tbSeatCard 
	local recordCard = {}
	local num 
	local player = self:getPlayer(playerid)
	local seatid
	local state = self:getState()
	if not player then 
		return false
	end
	seatid = player.seatid
	if not seatid or seatid == 0 then 
		return false
	end	
	if state ~= 'oper' then 
		return false
	end
	for i=3,self.cardNum do 
		recordCard[i] = 0
	end
	for k,v in pairs(self.seat_list) do 
		if k ~= seatid then
			tbSeatCard = self.tbCurSeatCard[k]
			for _,card in pairs(tbSeatCard) do 
				num = self.rule:getCardNum(card)
				recordCard[num] = recordCard[num] + 1				
			end
		end
	end
	local tb={}
	for k,v in pairs(recordCard) do 
		table.insert(tb,v)
	end
	-- log.debug("___recordCard__",tb)

	return tb
end

function Machine:getOutCards(playerid)
	local player = self:getPlayer(playerid)
	local seatid
	local state = self:getState()
	if not player then 
		return false
	end
	seatid = player.seatid
	if not seatid or seatid == 0 then 
		return false
	end		
	return self.tbOutCard
end

--离开桌子
function Machine:leaveTable(playerid)
	local player = self:getPlayer(playerid)
	print("__7777___self.curJuShu____",self.curJuShu)
	if self.curJuShu>0 or player.playing then 
		return false
	end
	log.debug('玩家离开牌桌>>>>>>>>>>>',playerid,self.managerid,self.tableid)
	if playerid == self.managerid then	
		--房主位置不清除
		player.ready = false	
		print("leaveTable房主离开桌子")		
		self:ntDisconnect(playerid)
		return true
	else
		--aa支付
		if self.curJuShu == 0 and self.payer==2 then 
			--返卡
			if player.ready then 
				local fangka = self:callGate(player, 'change_fangka', self.cost, reason)		
				if fangka then 				
				end				
			end
		end		
	end
	
	self:sitUp(playerid)
	self.player_list[playerid] = nil
	self:updatePlayerNum()
	return true
end

--掉线处理
function Machine:disconnect(playerid)	
	local player = self.player_list[playerid]
	local seatid = player.seatid
	log.debug('玩家掉线>>>>>>>>>>>',playerid,self.managerid,self.tableid,player.playing,player.disconnect)
	if  playerid==self.managerid then 
		print("disconnect房主不能离开桌子")		
		self:ntDisconnect(playerid)		
		return false
	end
	--旁观者掉线马上踢出大厅,房主不能离开桌子
	if self.curJushu==0 and not player.playing and player.disconnect then 
		print("########在旁观玩家中直接踢走")	
		self:sendGate(player, 'update_tableid', 0)
		self:sitUp(playerid)
		self.player_list[playerid] = nil
		return true
	else
		self:ntDisconnect(playerid)			
	end	
	return false
end

-------------------------------------------------------------------------------
-- 推送消息
-------------------------------------------------------------------------------
function Machine:ntStart()
	log.debug("__________pdk_start")
	local data = {pdk_nt_start={
 		tableid = self.tableid,	
 		paijuid = self.paijuid,
 		seatid = self.startSeatid,
 		first_card = self.firstCard,
	}}
	log.debug(data)
	self:sendToNoSeat(data)
end

function Machine:ntRest()
	local data = {pdk_nt_rest={
 		tableid = self.tableid,	
	}}
	self:sendToAll(data)	

end

--推送玩家操作
function Machine:ntOper(seatid,oldOperSeat)
	log.debug("__________pdk_oper",seatid,oldOperSeat)
	--1轮过后还是自己出牌
	if seatid == self.cardIsSeat then 
		--是炸弹
		if self.curCardType == self.rule.cardType.zhaDan then 			
			self:ntZhaDan(seatid)	
		end
	end
	--提示能出的牌
	self:getTipCards()

	local tbOper
	local oper 
	local tbOperRecord
	if oldOperSeat then
		local player = self:getPlayerBySeat(oldOperSeat)
		local cards = {}
		local code 
		if oldOperSeat == self.cardIsSeat then 
			cards = self.curCards
			code = self.curCardCode
		end
		oper = 2 --可出牌
		if player.oper == self.operList.play_next then 
			--不可出牌
			oper = 1
		end
		tbOper = {
			seatid = oldOperSeat,
			oper = oper,
			state = self:getPlayerState(player),
			cards = cards,
			code = code,
		}

		tbOperRecord = {
			seatid = oldOperSeat,
			oper = oper,
			cards = cards,
			playerid = player.playerid,		
		}
		if not self.tbCardRecord.game_oper[self.curRound] then 
			self.tbCardRecord.game_oper[self.curRound] = {}
		end	
		table.insert(self.tbCardRecord.game_oper[self.curRound],tbOperRecord)
	end
	
	local tbCurOper
	if seatid and self:getPlayerBySeat(seatid) then
		local player = self:getPlayerBySeat(seatid)
		tbCurOper = {
			seatid = seatid, --当前轮到操作的人
	 		oper_time = self.statusTime.oper,
	 		state = self:getPlayerState(player),
	 		button_list = self:getPlayerOperList(player),		
 		}
	end
	local code 
	if next(self.curCards) then 
		code = self.rule:getCardCode(self.curCards)
	end	
	local data = {pdk_nt_oper={
 		tableid = self.tableid,	
 		oper_round = self.curRound, 		
 		pre_oper = tbOper, 		
 		cur_oper = tbCurOper,	
	}}
	if self.operSeatid ~= self.cardIsSeat then 
		data.pdk_nt_oper.cards = self.curCards
		data.pdk_nt_oper.card_seat = self.cardIsSeat
		data.pdk_nt_oper.code = code
	end	
	if self.winnerSeatId then 
		data.pdk_nt_oper.cur_oper = nil
	end		
	log.debug("_______ntOper__________data__",data)
	self:sendToAll(data)
end

function Machine:ntEnd(endPlayers)
	-- local seatPlayers = self:getSeatPlayers()
	local data = {pdk_nt_end={
 		tableid = self.tableid,	
 		winer_seat = self.winnerSeatId,
 		end_player = endPlayers,
	}}	
	self:sendToAll(data)	
	log.debug("____ntEnd____",data)
end

function Machine:ntZhaDan(seatid)
	--对别的在座玩家扣币
	local winChip = self.bottomNum*5
	local money
	local player
	local tbPlayers = {}
	for sid,playerid in pairs(self.seat_list) do 
		if seatid ~= sid then
			player = self:getPlayer(playerid)
			player.chip = player.chip-winChip
			table.insert(tbPlayers,{seatid=sid,chip=player.chip,win_chip=-winChip})
			self.tbChipZhaDan[playerid] = self.tbChipZhaDan[playerid] - winChip
		end				
	end
	player = self:getPlayerBySeat(seatid)
	player.chip = player.chip+winChip*2
	table.insert(tbPlayers,{seatid=seatid,chip=player.chip,win_chip=winChip*2})
	self.tbChipZhaDan[player.playerid] = self.tbChipZhaDan[player.playerid] + winChip*2

	local data = {pdk_nt_zhadan={
 		tableid = self.tableid,			 		
 		seat_player = tbPlayers,
 		win_seat = seatid,
	}}	
	log.debug("____pdk_nt_zhadan_____",data)
	self:sendToAll(data)			
end

function Machine:ntReady(playerid,seatid)	
	local seatPlayer = {seatid=seatid,state=self.playerState.ready}
	local data = {pdk_nt_seat_change={
 		tableid = self.tableid,			 		
 		seat_player = seatPlayer, 	
 		playerid = playerid,	
 		seatid = seatid,
	}}	
	-- log.debug("__________data___",data)
	self:sendToAll(data)			
end

function Machine:ntNoAuto(playerid,seatid)	
	local seatPlayer = {seatid=seatid,state=self.playerState.playing}
	local data = {pdk_nt_seat_change={
 		tableid = self.tableid,			 		
 		seat_player = seatPlayer, 	
 		playerid = playerid,	
 		seatid = seatid,
	}}	
	-- log.debug("__________data___",data)
	self:sendToOther(playerid,data)			
end

--总结算通知
function Machine:ntFangkaEnd()

	self.fangkaEnd = true
	local endPlayers = {}
	for k,v in pairs(self.player_list) do 
		table.insert(endPlayers,{
			playerid=k,
			chip=v.chip,
			nick=v.nick,
			icon=v.icon,
			})
	end
	local data = {pdk_nt_fanka_end={
 		tableid = self.tableid,	
 		manager = self.managerid,
 		end_player = endPlayers,
 		end_time = os.time(),
 		config = self:getConfig(),
	}}	
	self:sendToAll(data)	
	log.debug("____pdk_nt_fanka_end____",data)

	--把所有人踢出房间后关闭服务
	self:voteTable()
	self.nodeMessage:callGlobalService('tablestate','close_private',playerid, self.tableid)		
end

function Machine:ntDisconnect(playerid)
	local player = self:getPlayer(playerid)
	local seatid = player.seatid
	local seatPlayer = {seatid=seatid,state=self.playerState.disconnect}
	local data = {pdk_nt_seat_change={
 		tableid = self.tableid,			 		
 		seat_player = seatPlayer, 	
 		playerid = playerid,	
 		seatid = seatid,
	}}	
	self:sendToOther(playerid,data)	
end

function Machine:ntOnconnect(playerid)
	local player = self:getPlayer(playerid)
	local seatid = player.seatid
	if not seatid or seatid==0 then 
		return 
	end
	local seatPlayer = {seatid=seatid,state=self.playerState.playing}
	local data = {pdk_nt_seat_change={
 		tableid = self.tableid,			 		
 		seat_player = seatPlayer, 	
 		playerid = playerid,	
 		seatid = seatid,
	}}	
	self:sendToOther(playerid,data)	
end

function Machine:voteTable()
	--把所有人踢出房间后关闭服务
	for k,v in pairs(self.player_list) do 	
		-- local data = {nt_kick_table = {
		-- 	playerid = k,
		-- 	content = '游戏结束请离场！',
		-- }}
		-- self:sendMessage(k,data)
		--设置玩家所在桌子id为0	
		self:sendGate(v, 'update_tableid', 0)
		self:sitUp(k)
		self.player_list[k] = nil
		self:updatePlayerNum()		
	end		
	self:exit()	
end

--投票解散
function Machine:ntCloseVote()	
	-- self.tbCloseVote[playerid] = true	
	print("____ntCloseVote____",self.tbCloseVote)
	local tbPlayer={}
	local player={}
	for k,v in pairs(self.player_list) do 
		player = {}
		player.nick = v.nick
		player.seatid = v.seatid
		player.playerid = v.playerid
		player.chip = v.chip
		player.diamond = v.diamond
		player.agree = (self.tbCloseVote[k] or 0)+1
		player.icon = v.icon
		table.insert(tbPlayer,player)
	end
	local data = {pdk_nt_close_vote={
 		tableid = self.tableid,	
 		vote_player = tbPlayer,
 		time = self.closeVoteTime,
 		managerid = self.managerid,
 		sourceid = self.sourceid,
	}}	
	self:sendToAll(data)	
	log.debug("____pdk_nt_close_vote____",data)

end

-------------------------------------------------------------------------------
-- 库存控制
-------------------------------------------------------------------------------
--计算机器人输赢
function Machine:robotSettlement()

end

--检查库存
function Machine:checkStock()
	return false
end

-------------------------------------------------------------------------------
-- 牌局记录
-------------------------------------------------------------------------------
function Machine:paijuRecord()
	local tableName = 'qclandlord_tablelog'
	local str = tableName .." (tid,trdid,svid,tlcnt,tllog,tltime,game,gameid,gametype,room_owner,room_flag)"
	-- log.debug("_________self.tbCardRecord___",self.tbCardRecord)
	local jsonStr = json.encode(self.tbCardRecord)
	if not jsonStr or jsonStr=='' then
		log.debug("_________jsonStr___",jsonStr)
	end
	local tlcnt = 3 --玩家数
	local game = 3		
	local sql = string.format("insert into %s value(%d,%d,%d,%d,'%s',%d,%d,%d,%d,%d,%s)",
		str,self.tableid,self.curJuShu,self.gameid,tlcnt,jsonStr,os.time(),game,self.gameid,self.roomid,self.managerid,self.room_flag)
	local res = skynet.call("mysql_log", "lua", "execute", sql)
	if not res then 
		return 
	end
	local tlid = res.insert_id
	if not tlid then 
		return
	end

	local time = os.time()
	self.tbCardRecord.game_config.end_time = time
	for k, v in pairs(self.tbCardRecord.game_end) do
		local wlfold = 0
		local player = self.player_list[v.playerid]
		local wlleft = v.chip
		local wlwin = v.win_chip + self.tbChipZhaDan[v.playerid]
		local wlflag = 2 --平局
		if wlwin > 0 then
			wlflag = 1
		else
			wlflag = 0 
		end
		local str1 = 'qclandlord_winlog' .. " (tlid, uid, pfid, usid, tid, room_id, svid, trdid, wlfold, wlleft, wlwin, wlflag, wltime, game, gameid, gametype)"
		local sql1 = string.format("insert into %s values(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d);", str1, tlid, v.playerid, player.pfid or 0, player.usid or 0,self.tableid, self.roomid, 14,
					 self.curJuShu, wlfold, wlleft, wlwin, wlflag, time, player.game or 0,self.gameid, self.roomid)
		local res = skynet.call("mysql_log", "lua", "execute", sql1)
		print("-------------------------------->res sql1",res, sql1)
	end
end




-----------------------------------------------------------------------------------
----------------------------------
-- 数据操作
----------------------------------


--桌子相关配置
function Machine:getConfig()
	return {
		bottom_num	= self.bottomNum,	-- 底分		
		time_wait = self.statusTime.wait,
		time_rest = self.statusTime.rest,
		time_start = self.statusTime.start,
		time_end = self.statusTime.settlement,	
		time_oper = self.statusTime.oper,
		card_num = self.cardNum,
		max_jushu = self.maxJuShu,
		cur_jushu = self.curJuShu,
		table_num = self.tableNum,
		managerid = self.managerid,
		pay_type = self.payer,
		close_time = self.maxWaitTime-self.waitTime,
		table_flag = self.room_flag,
	}
end

--取牌
function Machine:getCard(playerid,num)
	local tbCard = {}
	local playerCard = self.gmcards[playerid] 
	local delCard = {}
	if playerCard and #playerCard>0 and self.tbCheatNum[playerid] > 0 then --有配牌		
		self.tbCheatNum[playerid] = self.tbCheatNum[playerid] - 1
		if self.tbCheatNum[playerid] == 0 then
			self.gmcards[playerid] = {}
		end	
		if num == 1 then 
			table.insert(tbCard,playerCard[5])
		else
			for i=1,num do 
				table.insert(tbCard,playerCard[i])
			end
		end
		return tbCard
	end
	return self.rule:getCard(num)
end


----------------------------------------------------------------------------------------------
---------开始游戏
---------------------------------------------------------------------------------------------- 
function Machine:start()
	self.fsm:set("settlement")
	self.fsm:fire("to_rest")
end

return Machine